package com.wrupple.muba.catalogs.client.widgets.colorPicker;

/**
 * Copyright (c) 2007, AurorisNET.
 *
 * Everyone is permitted to copy and distribute verbatim copies of this license
 * document, but changing it is not allowed.
 *
 * Preamble
 *
 * This license establishes the terms under which a given free software Package
 * may be copied, modified, distributed, and/or redistributed. The intent is
 * that the Copyright Holder maintains some artistic control over the
 * development of that Package while still keeping the Package available as open
 * source and free software.
 *
 * You are always permitted to make arrangements wholly outside of this license
 * directly with the Copyright Holder of a given Package. If the terms of this
 * license do not permit the full use that you propose to make of the Package,
 * you should contact the Copyright Holder and seek a different licensing
 * arrangement.
 *
 * Definitions
 *
 * "Copyright Holder" means the individual(s) or organization(s) named in the
 * copyright notice for the entire Package.
 *
 * "Contributor" means any party that has contributed code or other material to
 * the Package, in accordance with the Copyright Holder's procedures.
 *
 * "You" and "your" means any person who would like to copy, distribute, or
 * modify the Package.
 *
 * "Package" means the collection of files distributed by the Copyright Holder,
 * and derivatives of that collection and/or of those files. A given Package may
 * consist of either the Standard Version, or a Modified Version.
 *
 * "Distribute" means providing a copy of the Package or making it accessible to
 * anyone else, or in the case of a company or organization, to others outside
 * of your company or organization.
 *
 * "Distributor Fee" means any fee that you charge for Distributing this Package
 * or providing support for this Package to another party. It does not mean
 * licensing fees.
 *
 * "Standard Version" refers to the Package if it has not been modified, or has
 * been modified only in ways explicitly requested by the Copyright Holder.
 *
 * "Modified Version" means the Package, if it has been changed, and such
 * changes were not explicitly requested by the Copyright Holder.
 *
 * "Original License" means this Artistic License as Distributed with the
 * Standard Version of the Package, in its current version or as it may be
 * modified by The Perl Foundation in the future.
 *
 * "Source" form means the source code, documentation source, and configuration
 * files for the Package.
 *
 * "Compiled" form means the compiled bytecode, object code, binary, or any
 * other form resulting from mechanical transformation or translation of the
 * Source form.
 *
 * Permission for Use and Modification Without Distribution
 *
 * (1) You are permitted to use the Standard Version and create and use Modified
 * Versions for any purpose without restriction, provided that you do not
 * Distribute the Modified Version.
 *
 * Permissions for Redistribution of the Standard Version
 *
 * (2) You may Distribute verbatim copies of the Source form of the Standard
 * Version of this Package in any medium without restriction, either gratis or
 * for a Distributor Fee, provided that you duplicate all of the original
 * copyright notices and associated disclaimers. At your discretion, such
 * verbatim copies may or may not include a Compiled form of the Package.
 *
 * (3) You may apply any bug fixes, portability changes, and other modifications
 * made available from the Copyright Holder. The resulting Package will still be
 * considered the Standard Version, and as such will be subject to the Original
 * License.
 *
 * Distribution of Modified Versions of the Package as Source
 *
 * (4) You may Distribute your Modified Version as Source (either gratis or for
 * a Distributor Fee, and with or without a Compiled form of the Modified
 * Version) provided that you clearly document how it differs from the Standard
 * Version, including, but not limited to, documenting any non-standard
 * features, executables, or modules, and provided that you do at least ONE of
 * the following:
 *
 *      (a) make the Modified Version available to the Copyright Holder of the
 *          Standard Version, under the Original License, so that the Copyright
 *          Holder may include your modifications in the Standard Version.
 *
 *      (b) ensure that installation of your Modified Version does not prevent
 *          the user installing or running the Standard Version. In addition,
 *          the Modified Version must bear a name that is different from the
 *          name of the Standard Version.
 *
 *      (c) allow anyone who receives a copy of the Modified Version to make the
 *          Source form of the Modified Version available to others under
 *
 *          (i) the Original License or
 *
 *          (ii) a license that permits the licensee to freely copy, modify and
 *              redistribute the Modified Version using the same licensing terms
 *              that apply to the copy that the licensee received, and requires
 *              that the Source form ofthe Modified Version, and of any works
 *              derived from it, be made freely available in that license fees
 *              are prohibited but Distributor Fees are allowed.
 *
 * Distribution of Compiled Forms of the Standard Version or Modified Versions
 * without the Source
 *
 * (5) You may Distribute Compiled forms of the Standard Version without the
 * Source, provided that you include complete instructions on how to get the
 * Source of the Standard Version. Such instructions must be valid at the time
 * of your distribution. If these instructions, at any time while you are
 * carrying out such distribution, become invalid, you must provide new
 * instructions on demand or cease further distribution. If you provide valid
 * instructions or cease distribution within thirty days after you become aware
 * that the instructions are invalid, then you do not forfeit any of your rights
 * under this license.
 *
 * (6) You may Distribute a Modified Version in Compiled form without the
 * Source, provided that you comply with Section 4 with respect to the Source of
 * the Modified Version.
 *
 * Aggregating or Linking the Package
 *
 * (7) You may aggregate the Package (either the Standard Version or Modified
 * Version) with other packages and Distribute the resulting aggregation
 * provided that you do not charge a licensing fee for the Package. Distributor
 * Fees are permitted, and licensing fees for other components in the
 * aggregation are permitted. The terms of this license apply to the use and
 * Distribution of the Standard or Modified Versions as included in the
 * aggregation.
 *
 * (8) You are permitted to link Modified and Standard Versions with other
 * works, to embed the Package in a larger work of your own, or to build
 * stand-alone binary or bytecode versions of applications that include the
 * Package, and Distribute the result without restriction, provided the result
 * does not expose a direct interface to the Package.
 *
 * Items That are Not Considered Part of a Modified Version
 *
 * (9) Works (including, but not limited to, modules and scripts) that merely
 * extend or make use of the Package, do not, by themselves, cause the Package
 * to be a Modified Version. In addition, such works are not considered parts of
 * the Package itself, and are not subject to the terms of this license.
 *
 * General Provisions
 *
 * (10) Any use, modification, and distribution of the Standard or Modified
 * Versions is governed by this Artistic License. By using, modifying or
 * distributing the Package, you accept this license. Do not use, modify, or
 * distribute the Package, if you do not accept this license.
 *
 * (11) If your Modified Version has been derived from a Modified Version made
 * by someone other than you, you are nevertheless required to ensure that your
 * Modified Version complies with the requirements of this license.
 *
 * (12) This license does not grant you the right to use any trademark, service
 * mark, tradename, or logo of the Copyright Holder.
 *
 * (13) This license includes the non-exclusive, worldwide, free-of-charge
 * patent license to make, have made, use, offer to sell, sell, import and
 * otherwise transfer the Package with respect to any patent claims licensable
 * by the Copyright Holder that are necessarily infringed by the Package. If you
 * institute patent litigation (including a cross-claim or counterclaim) against
 * any party alleging that the Package constitutes direct or contributory patent
 * infringement, then this Artistic License to you shall terminate on the date
 * that such litigation is filed.
 *
 * (14) Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER
 * AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
 * NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW.
 * UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY
 * OUT OF THE USE OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 */

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasValue;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.RadioButton;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;

/**
 * This is the implementation of the Colorpicker. It defines the user interface, the glue and calculations necessary for colorpicker functionality.
 *
 * <h1>Example</h1>
 * <CODE>
 * public class ColorPickerExample implements EntryPoint {
 *
 *  public void onModuleLoad() {
 *    // Make a new colorpicker
 *    ColorPicker picker = new ColorPicker();
 *
 *    // Add it to the root panel.
 *    RootPanel.get().add(picker);
 *
 *    // Make a new button that does something when you click it.
 *    Button b = new Button("Pick!", new ClickListener() {
 *      public void onClick(Widget sender) {
 *        Window.alert("You chose " + picker.getHexColor());
 *      }
 *    });
 *
 *    // Add it to the root panel.
 *    RootPanel.get().add(b);
 *  }
 * }
 * </CODE>
 * @author AurorisNET
 * @copyright (C) 2007 AurorisNET. All Rights Reserved.
 */
public class ColorPicker extends Composite implements KeyPressHandler, ClickHandler, ChangeHandler, HasValue<String>
{
    private int blue;
    private int brightness;
    private int colorMode; // Which color picking mode we are in

    // Elements
        private HTML colorpreview;
    private int green;
    private int hue;
    private RadioButton rbBlue;
    private RadioButton rbBrightness;
    private RadioButton rbGreen;
    // Radiobuttons
    private RadioButton rbHue;

    private RadioButton rbRed;
    private RadioButton rbSaturation;
    private int red;
    private int saturation;
    private SliderBar sliderbar; // auxilliary color picking slider. Center UI component.
    private SliderMap slidermap; // main color picking slider. Leftmost UI component.

    private TextBox tbBlue;
    private TextBox tbBrightness;
    private TextBox tbGreen;
    private TextBox tbHexColor;
    // Textboxes
    private TextBox tbHue;
    private TextBox tbRed;
    private TextBox tbSaturation;

    public ColorPicker()
    {
        // UI Drawing
        //------------------

        hue = 0;
        saturation = 100;
        brightness = 100;
        red = 255;
        green = 0;
        blue = 0;

        HorizontalPanel panel = new HorizontalPanel();
        FlexTable table = new FlexTable();

        // Add the large slider map
        slidermap = new SliderMap(this);
        panel.add(slidermap);
        panel.setCellWidth(slidermap, "258px");
        panel.setCellHeight(slidermap, "258px");

        // Add the small slider bar
        sliderbar = new SliderBar(this);
        panel.add(sliderbar);
        panel.setCellWidth(sliderbar, "40px");
        panel.setCellHeight(sliderbar, "258px");

        // Define the Flextable's content
        // Color preview at the top
        colorpreview = new HTML("");
        colorpreview.setWidth("50px");
        colorpreview.setHeight("50px");
        DOM.setStyleAttribute(colorpreview.getElement(), "border", "1px solid black");

        // Radio buttons
        rbHue = new RadioButton("color", "H:");
        rbHue.addClickHandler(this);
        rbSaturation = new RadioButton("color", "S:");
        rbSaturation.addClickHandler(this);
        rbBrightness = new RadioButton("color", "V:");
        rbBrightness.addClickHandler(this);
        rbRed = new RadioButton("color", "R:");
        rbRed.addClickHandler(this);
        rbGreen = new RadioButton("color", "G:");
        rbGreen.addClickHandler(this);
        rbBlue = new RadioButton("color", "B:");
        rbBlue.addClickHandler(this);

        // Textboxes
        tbHue = new TextBox();
        tbHue.setText(new Integer(hue).toString());
        tbHue.setMaxLength(3);
        tbHue.setVisibleLength(4);
        tbHue.addKeyPressHandler(this);
        tbHue.addChangeHandler(this);
        tbSaturation = new TextBox();
        tbSaturation.setText(new Integer(saturation).toString());
        tbSaturation.setMaxLength(3);
        tbSaturation.setVisibleLength(4);
        tbSaturation.addKeyPressHandler(this);
        tbSaturation.addChangeHandler(this);
        tbBrightness = new TextBox();
        tbBrightness.setText(new Integer(brightness).toString());
        tbBrightness.setMaxLength(3);
        tbBrightness.setVisibleLength(4);
        tbBrightness.addKeyPressHandler(this);
        tbBrightness.addChangeHandler(this);
        tbRed = new TextBox();
        tbRed.setText(new Integer(red).toString());
        tbRed.setMaxLength(3);
        tbRed.setVisibleLength(4);
        tbRed.addKeyPressHandler(this);
        tbRed.addChangeHandler(this);
        tbGreen = new TextBox();
        tbGreen.setText(new Integer(green).toString());
        tbGreen.setMaxLength(3);
        tbGreen.setVisibleLength(4);
        tbGreen.addKeyPressHandler(this);
        tbGreen.addChangeHandler(this);
        tbBlue = new TextBox();
        tbBlue.setText(new Integer(blue).toString());
        tbBlue.setMaxLength(3);
        tbBlue.setVisibleLength(4);
        tbBlue.addKeyPressHandler(this);
        tbBlue.addChangeHandler(this);
        tbHexColor = new TextBox();
        tbHexColor.setText("ff0000");
        tbHexColor.setMaxLength(6);
        tbHexColor.setVisibleLength(6);
        tbHexColor.addKeyPressHandler(this);
        tbHexColor.addChangeHandler(this);

        // Put together the FlexTable
        table.setWidget(0, 0, colorpreview);
        table.getFlexCellFormatter().setColSpan(0, 0, 3);
        table.setWidget(1, 0, rbHue);
        table.setWidget(1, 1, tbHue);
        table.setWidget(1, 2, new HTML("&deg;"));
        table.setWidget(2, 0, rbSaturation);
        table.setWidget(2, 1, tbSaturation);
        table.setText(2, 2, "%");
        table.setWidget(3, 0, rbBrightness);
        table.setWidget(3, 1, tbBrightness);
        table.setText(3, 2, "%");
        table.setWidget(4, 0, rbRed);
        table.setWidget(4, 1, tbRed);
        table.setWidget(5, 0, rbGreen);
        table.setWidget(5, 1, tbGreen);
        table.setWidget(6, 0, rbBlue);
        table.setWidget(6, 1, tbBlue);
        table.setText(7,0, "#:");
        table.setWidget(7,1, tbHexColor);
        table.getFlexCellFormatter().setColSpan(7, 1, 2);

        // Final setup
        panel.add(table);
        rbSaturation.setValue(true);
        setPreview("ff0000");
        DOM.setStyleAttribute(colorpreview.getElement(), "cursor", "default");

        // First event
        onClick(rbSaturation);

        initWidget(panel);
    }

    /**
     * Returns the hexadecimal notation of the current selected color.
     * @return Hexadecimal in the range of 000000-FFFFFF
     */
    public String getHexColor()
    {
        return tbHexColor.getText();
    }

    /**
     * This method is called when a widget is attached to the browser's document. To receive notification after a Widget has been added to the document, override the Widget.onLoad() method.
     *
     * Subclasses that override this method must call <tt>super.onAttach()</tt> before doing anything else to ensure that the Widget has been properly attached to its underlying Element.
     */
    @Override
    public void onAttach()
    {
        // Called when we are shown (from being hidden)
        super.onAttach();
        colorMode = -1;
        updateSliders();
    }

    /**
     * Fires whenever the user generates picking events along the color picker bar.
     *
     * Subclasses that override this method must call <tt>super.onBarSelected(y)</tt> to ensure that the Widget recieves its events.
     * @param y the distance along the y-axis of the user's selection, between 0 and 255, inclusive.
     */
    public void onBarSelected(int y)
    {
        switch (colorMode)
        {
            case SliderMap.Hue:
                hue = 360 - percentOf(y, 360);
                tbHue.setText(Integer.toString(hue));
                onChange(tbHue);
                break;
            case SliderMap.Saturation:
                saturation = 100 - percentOf(y, 100);
                tbSaturation.setText(Integer.toString(saturation));
                onChange(tbSaturation);
                break;
            case SliderMap.Brightness:
                brightness = 100 - percentOf(y, 100);
                tbBrightness.setText(Integer.toString(brightness));
                onChange(tbBrightness);
                break;
            case SliderMap.Red:
                red = 255 - y;
                tbRed.setText(Integer.toString(red));
                onChange(tbRed);
                break;
            case SliderMap.Green:
                green = 255 - y;
                tbGreen.setText(Integer.toString(green));
                onChange(tbGreen);
                break;
            case SliderMap.Blue:
                blue = 255 - y;
                tbBlue.setText(Integer.toString(blue));
                onChange(tbBlue);
                break;
        }
    }

    /*
     * (non-Javadoc)
     * @see com.google.gwt.event.dom.client.ChangeHandler#onChange(com.google.gwt.event.dom.client.ChangeEvent)
     */
    public void onChange(ChangeEvent event)
    {
        onChange((Widget)event.getSource());
    }

    /**
     * Fired whenever something in this widget changes.
     *
     * Subclasses that override this method must call <tt>super.onChange(sender)</tt> to ensure that the Widget recieves its events.
     * @param sender the widget that has changed.
     */
    public void onChange(Widget sender)
    {
        if (sender == tbHexColor)
        {
            // Figure out colors
            // Color class will do bounds check on hex input
            try
            {
                ColorPickerColor colorPickerColor = new ColorPickerColor();
                colorPickerColor.setHex(tbHexColor.getText());
                tbHue.setText(Integer.toString(colorPickerColor.getHue()));
                tbSaturation.setText(Integer.toString(colorPickerColor.getSaturation()));
                tbBrightness.setText(Integer.toString(colorPickerColor.getValue()));
                tbRed.setText(Integer.toString(colorPickerColor.getRed()));
                tbGreen.setText(Integer.toString(colorPickerColor.getGreen()));
                tbBlue.setText(Integer.toString(colorPickerColor.getBlue()));
                tbHexColor.setText(colorPickerColor.getHex());
                setPreview(colorPickerColor.getHex());
            }
            catch (Exception e)
            {
            }
        }

        if (sender == tbRed || sender == tbGreen || sender == tbBlue)
        {
            // Don't allow this value to overflow or underflow
            try
            {
                if (Integer.parseInt(((TextBox)sender).getText()) > 255)
                {
                    ((TextBox)sender).setText("255");
                }
                if (Integer.parseInt(((TextBox)sender).getText()) < 0)
                {
                    ((TextBox)sender).setText("0");
                }
            }
            catch (Exception e)
            {
            }

            red = Integer.parseInt(tbRed.getText());
            green = Integer.parseInt(tbGreen.getText());
            blue = Integer.parseInt(tbBlue.getText());
            hue = Integer.parseInt(tbHue.getText());
            saturation = Integer.parseInt(tbSaturation.getText());
            brightness = Integer.parseInt(tbBrightness.getText());

            // Figure out the colors
            try
            {
                ColorPickerColor colorPickerColor = new ColorPickerColor();
                colorPickerColor.setRGB(red, green, blue);
                tbHue.setText(Integer.toString(colorPickerColor.getHue()));
                tbSaturation.setText(Integer.toString(colorPickerColor.getSaturation()));
                tbBrightness.setText(Integer.toString(colorPickerColor.getValue()));
                tbHexColor.setText(colorPickerColor.getHex());
                setPreview(colorPickerColor.getHex());
            }
            catch (Exception e)
            {
            }
        }
        else if (sender == tbHue || sender == tbSaturation || sender == tbBrightness)
        {
            // Don't allow this value to overflow
            try
            {
                if (Integer.parseInt(tbHue.getText()) > 359)
                {
                    tbHue.setText("359");
                }

                if (Integer.parseInt(tbSaturation.getText()) > 100)
                {
                    tbSaturation.setText("100");
                }

                if (Integer.parseInt(tbBrightness.getText()) > 100)
                {
                    tbBrightness.setText("100");
                }
            }
            catch (Exception e)
            {
            }

            red = Integer.parseInt(tbRed.getText());
            green = Integer.parseInt(tbGreen.getText());
            blue = Integer.parseInt(tbBlue.getText());
            hue = Integer.parseInt(tbHue.getText());
            saturation = Integer.parseInt(tbSaturation.getText());
            brightness = Integer.parseInt(tbBrightness.getText());

            // Figure out colors
            try
            {
                ColorPickerColor colorPickerColor = new ColorPickerColor();
                colorPickerColor.setHSV(hue, saturation, brightness);
                tbRed.setText(Integer.toString(colorPickerColor.getRed()));
                tbGreen.setText(Integer.toString(colorPickerColor.getGreen()));
                tbBlue.setText(Integer.toString(colorPickerColor.getBlue()));
                tbHexColor.setText(colorPickerColor.getHex());
                setPreview(colorPickerColor.getHex());
            }
            catch (Exception e)
            {
            }
        }

        // Let the sliders know something's changed
        updateSliders();
    }

    /*
     * (non-Javadoc)
     * @see com.google.gwt.event.dom.client.ClickHandler#onClick(com.google.gwt.event.dom.client.ClickEvent)
     */
    public void onClick(ClickEvent event)
    {
        onClick((Widget)event.getSource());
    }

    /**
     * Fired when the user clicks on a widget.
     *
     * Subclasses that override this method must call <tt>super.onClick(sender)</tt> to ensure that the Widget recieves its events.
     * @param sender the widget sending the event.
     */
    public void onClick(Widget sender)
    {
        if (sender == rbHue)
        {
            if (colorMode != SliderMap.Hue)
            {
                colorMode = SliderMap.Hue;
                slidermap.setColorSelectMode(SliderMap.Hue);
                sliderbar.setColorSelectMode(SliderBar.Hue);
                slidermap.setOverlayOpacity(100);
                sliderbar.setLayerOpacity(100, SliderBar.BarD);
            }

            try
            {
                ColorPickerColor colorPickerColor = new ColorPickerColor();
                colorPickerColor.setHSV(hue, 100, 100);
                slidermap.setOverlayColor("#" + colorPickerColor.getHex());
            }
            catch (Exception e) {}

            sliderbar.setSliderPosition(256 - (int)((new Integer(hue).floatValue() / 360) * 256));
            slidermap.setSliderPosition((int)((new Integer(saturation).floatValue() / 100) * 256),
                                        256 - (int)((new Integer(brightness).floatValue() / 100) * 256));
        }
        else if(sender == rbSaturation)
        {
            if (colorMode != SliderMap.Saturation)
            {
                colorMode = SliderMap.Saturation;
                slidermap.setColorSelectMode(SliderMap.Saturation);
                sliderbar.setColorSelectMode(SliderBar.Saturation);
                slidermap.setOverlayColor("transparent");
                sliderbar.setLayerColor("#ffffff", SliderBar.BarC);
                sliderbar.setLayerOpacity(100, SliderBar.BarD);
            }

            slidermap.setOverlayOpacity(100 - saturation);
            sliderbar.setLayerColor(tbHexColor.getText(), SliderBar.BarD);

            sliderbar.setSliderPosition(256 - (int)((new Integer(saturation).floatValue() / 100) * 256));
            slidermap.setSliderPosition((int)((new Integer(hue).floatValue() / 360) * 256),
                                        256 - (int)((new Integer(brightness).floatValue() / 100) * 256));
        }
        else if(sender == rbBrightness)
        {
            if (colorMode != SliderMap.Brightness)
            {
                colorMode = SliderMap.Brightness;
                slidermap.setColorSelectMode(SliderMap.Brightness);
                sliderbar.setColorSelectMode(SliderBar.Brightness);
                slidermap.setUnderlayColor("#000000");
                slidermap.setOverlayColor("transparent");
                sliderbar.setLayerOpacity(100, SliderBar.BarD);
            }

            try
            {
                ColorPickerColor colorPickerColor = new ColorPickerColor();
                colorPickerColor.setHSV(hue, saturation, 100);
                sliderbar.setLayerColor("#" + colorPickerColor.getHex(), SliderBar.BarD);
            }
            catch (Exception e) {}

            slidermap.setOverlayOpacity(brightness);

            sliderbar.setSliderPosition(256 - (int)((new Integer(brightness).floatValue() / 100) * 256));
            slidermap.setSliderPosition((int)((new Integer(hue).floatValue() / 360) * 256),
                                        256 - (int)((new Integer(saturation).floatValue() / 100) * 256));
        }
        else if(sender == rbRed)
        {
            if (colorMode != SliderMap.Red)
            {
                colorMode = SliderMap.Red;
                slidermap.setColorSelectMode(SliderMap.Red);
                sliderbar.setColorSelectMode(SliderBar.Red);
            }
            slidermap.setOverlayOpacity(percentOf(red, 100));

            sliderbar.setSliderPosition(256 - red);
            slidermap.setSliderPosition(blue, 256 - green);
        }
        else if(sender == rbGreen)
        {
            if (colorMode != SliderMap.Green)
            {
                colorMode = SliderMap.Green;
                slidermap.setColorSelectMode(SliderMap.Green);
                sliderbar.setColorSelectMode(SliderBar.Green);
            }

            slidermap.setOverlayOpacity(percentOf(green, 100));

            sliderbar.setSliderPosition(256 - green);
            slidermap.setSliderPosition(blue, 256 - red);
        }
        else if(sender == rbBlue)
        {
            if (colorMode != SliderMap.Blue)
            {
                colorMode = SliderMap.Blue;
                slidermap.setColorSelectMode(SliderMap.Blue);
                sliderbar.setColorSelectMode(SliderBar.Blue);
            }

            slidermap.setOverlayOpacity(percentOf(blue, 100));

            sliderbar.setSliderPosition(256 - blue);
            slidermap.setSliderPosition(red, 256 - green);
        }

        if (colorMode == SliderMap.Red || colorMode == SliderMap.Green || colorMode == SliderMap.Blue)
        {
            int x = 0;
            int y = 0;

            if (colorMode == SliderMap.Red)
            {
                x = blue;
                y = green;
            }

            if (colorMode == SliderMap.Green)
            {
                x = blue;
                y = red;
            }

            if (colorMode == SliderMap.Blue)
            {
                x = red;
                y = green;
            }

            int horzPer = (int)((new Float(x).floatValue() / 256) * 100);
            int vertPer = (int)((new Float(y).floatValue() / 256) * 100);
            int horzPerRev = (int)(((256 - new Float(x).floatValue()) / 256) * 100);
            int vertPerRev = (int)(((256 - new Float(y).floatValue()) / 256) * 100);

            if (vertPerRev > horzPerRev)
                sliderbar.setLayerOpacity(horzPerRev, SliderBar.BarD);
            else
                sliderbar.setLayerOpacity(vertPerRev, SliderBar.BarD);
            if (vertPerRev > horzPer)
                sliderbar.setLayerOpacity(horzPer, SliderBar.BarC);
            else
                sliderbar.setLayerOpacity(vertPerRev, SliderBar.BarC);
            if (vertPer > horzPer)
                sliderbar.setLayerOpacity(horzPer, SliderBar.BarB);
            else
                sliderbar.setLayerOpacity(vertPer, SliderBar.BarB);
            if (vertPer > horzPerRev)
                sliderbar.setLayerOpacity(horzPerRev, SliderBar.BarA);
            else
                sliderbar.setLayerOpacity(vertPer, SliderBar.BarA);
        }
    }

    /**
     * Fired when a keyboard action generates a character. This occurs after onKeyDown and onKeyUp are fired for the physical key that was pressed.
     *
     * It should be noted that many browsers do not generate keypress events for non-printing keyCode values, such as KEY_ENTER or arrow keys. These keyCodes can be reliably captured either with onKeyDown(Widget, char, int) or onKeyUp(Widget, char, int).
     *
     * Subclasses that override this method must call <tt>super.onKeyPress(sender, keyCode, modifiers)</tt> to ensure that the Widget recieves its events.
     * @param sender the widget that was focused when the event occurred.
     * @see com.google.gwt.user.client.ui.KeyboardListener
     */
    public void onKeyPress(KeyPressEvent event)
    {
        Widget sender = (Widget) event.getSource();
        char keyCode = event.getCharCode();

        if (sender == tbHexColor)
        {
            // Disallow non-hex in hexadecimal boxes
            if ((!Character.isDigit(keyCode))
                && (keyCode != 'A') && (keyCode != 'a')
                && (keyCode != 'B') && (keyCode != 'b')
                && (keyCode != 'C') && (keyCode != 'c')
                && (keyCode != 'D') && (keyCode != 'd')
                && (keyCode != 'E') && (keyCode != 'e')
                && (keyCode != 'F') && (keyCode != 'f')
                && (keyCode != (char) KeyCodes.KEY_TAB)
                && (keyCode != (char) KeyCodes.KEY_BACKSPACE)
                && (keyCode != (char) KeyCodes.KEY_DELETE) && (keyCode != (char) KeyCodes.KEY_ENTER)
                && (keyCode != (char) KeyCodes.KEY_HOME) && (keyCode != (char) KeyCodes.KEY_END)
                && (keyCode != (char) KeyCodes.KEY_LEFT) && (keyCode != (char) KeyCodes.KEY_UP)
                && (keyCode != (char) KeyCodes.KEY_RIGHT) && (keyCode != (char) KeyCodes.KEY_DOWN))
            {
                ((TextBox)sender).cancelKey();
            }
        }
        else
        {
            // Disallow non-numerics in numeric boxes
            if ((!Character.isDigit(keyCode))
                && (keyCode != (char) KeyCodes.KEY_TAB)
                && (keyCode != (char) KeyCodes.KEY_BACKSPACE)
                && (keyCode != (char) KeyCodes.KEY_DELETE) && (keyCode != (char) KeyCodes.KEY_ENTER)
                && (keyCode != (char) KeyCodes.KEY_HOME) && (keyCode != (char) KeyCodes.KEY_END)
                && (keyCode != (char) KeyCodes.KEY_LEFT) && (keyCode != (char) KeyCodes.KEY_UP)
                && (keyCode != (char) KeyCodes.KEY_RIGHT) && (keyCode != (char) KeyCodes.KEY_DOWN))
            {
                ((TextBox)sender).cancelKey();
            }
        }
    }

    /**
     * Fires whenever the user generates picking events on the color picker map.
     *
     * Subclasses that override this method must call <tt>super.onMapSelected(x,y)</tt> to ensure that the Widget recieves its events.
     * @param x the distance along the x-axis of the user's selection, between 0 and 255, inclusive.
     * @param y the distance along the y-axis of the user's selection, between 0 and 255, inclusive.
     */
    public void onMapSelected(int x, int y)
    {
        switch (colorMode)
        {
            case SliderMap.Hue:
                saturation = percentOf(x, 100);
                brightness = 100 - percentOf(y, 100);
                tbSaturation.setText(Integer.toString(saturation));
                tbBrightness.setText(Integer.toString(brightness));
                onChange(tbHue);
                break;
            case SliderMap.Saturation:
                hue = percentOf(x, 360);
                brightness = 100 - percentOf(y, 100);
                tbHue.setText(Integer.toString(hue));
                tbBrightness.setText(Integer.toString(brightness));
                onChange(tbSaturation);
                break;
            case SliderMap.Brightness:
                hue = percentOf(x, 360);
                saturation = 100 - percentOf(y, 100);
                tbHue.setText(Integer.toString(hue));
                tbSaturation.setText(Integer.toString(saturation));
                onChange(tbBrightness);
                break;
            case SliderMap.Red:
                blue = x;
                green = 256 - y;
                tbBlue.setText(Integer.toString(blue));
                tbGreen.setText(Integer.toString(green));
                onChange(tbRed);
                break;
            case SliderMap.Green:
                blue = x;
                red = 256 - y;
                tbBlue.setText(Integer.toString(blue));
                tbRed.setText(Integer.toString(red));
                onChange(tbGreen);
                break;
            case SliderMap.Blue:
                red = x;
                green = 256 - y;
                tbRed.setText(Integer.toString(red));
                tbGreen.setText(Integer.toString(green));
                onChange(tbBlue);
                break;
        }
    }

    /*Helper functions -- for common calculations
     */
    /**
     * Divides the first value by 256, then multiplies it by the second value.
     * @param val1 first value.
     * @param val2 second value.
     * @return result.
     */
    private int percentOf(int val1, int val2)
    {
        return (int)(new Float(val1).floatValue() / 256 * val2);
    }

    /**
     * Sets the hexadecimal notation for Red, Green, and Blue. This will automatically populate all the other fields, too.
     * @param hex Hexadecimal notation of Red, Green and Blue in the range of 000000-FFFFFF
     * @throws java.lang.Exception A generic exception if the hexadecimal notation is bad.
     */
    public void setHex(String hex) throws Exception
    {
        ColorPickerColor colorPickerColor = new ColorPickerColor();
        colorPickerColor.setHex(hex);

        this.red = colorPickerColor.getRed();
        this.green = colorPickerColor.getGreen();
        this.blue = colorPickerColor.getBlue();
        this.hue = colorPickerColor.getHue();
        this.saturation = colorPickerColor.getSaturation();
        this.brightness = colorPickerColor.getValue();

        tbRed.setText(Integer.toString(this.red));
        tbGreen.setText(Integer.toString(this.green));
        tbBlue.setText(Integer.toString(this.blue));
        tbHue.setText(Integer.toString(this.hue));
        tbSaturation.setText(Integer.toString(this.saturation));
        tbBrightness.setText(Integer.toString(this.brightness));
        tbHexColor.setText(colorPickerColor.getHex());
        setPreview(colorPickerColor.getHex());

        updateSliders();
    }

    /**
     * Set the Hue, Saturation and Value (Brightness) variables. This will automatically populate the Red, Green, Blue, and Hexadecimal fields, too.
     *
     * HSV represents points in the RGB color space, which attempt to describe perceptual color relationships more accurately than RGB. HSV describes colors as points in a cylinder whose central axis ranges from black at the bottom to white at the top with neutral colors between them, where angle around the axis corresponds to �hue�, distance from the axis corresponds to �saturation�, and distance along the axis corresponds to �lightness�, �value�, or �brightness�.
     * @param hue angle - valid range is 0-359
     * @param saturation percent - valid range is 0-100
     * @param value percent (Brightness) - valid range is 0-100
     * @throws java.lang.Exception A general exception if the Hue, Saturation, or Value variables are out of range.
     */
    public void setHSV(int hue, int saturation, int value) throws Exception
    {
        ColorPickerColor colorPickerColor = new ColorPickerColor();
        colorPickerColor.setHSV(hue, saturation, value);

        this.red = colorPickerColor.getRed();
        this.green = colorPickerColor.getGreen();
        this.blue = colorPickerColor.getBlue();
        this.hue = hue;
        this.saturation = saturation;
        this.brightness = value;

        tbRed.setText(Integer.toString(this.red));
        tbGreen.setText(Integer.toString(this.green));
        tbBlue.setText(Integer.toString(this.blue));
        tbHue.setText(Integer.toString(this.hue));
        tbSaturation.setText(Integer.toString(this.saturation));
        tbBrightness.setText(Integer.toString(this.brightness));
        tbHexColor.setText(colorPickerColor.getHex());
        setPreview(colorPickerColor.getHex());

        updateSliders();
    }

    /**
     * Called when the widget wants to update the preview color sample box in the top-right corner of the UI.
     * @param hex Hexadecimal notation of RGB
     */
    private void setPreview(String hex)
    {
        DOM.setStyleAttribute(colorpreview.getElement(), "backgroundColor", "#" + hex);
    }

    /**
     * Sets the Red, Green, and Blue color variables. This will automatically populate the Hue, Saturation and Brightness and Hexadecimal fields, too.
     *
     * The RGB color model is an additive color model in which red, green, and blue light are added together in various ways to reproduce a broad array of colors. The name of the model comes from the initials of the three additive primary colors, red, green, and blue.
     * @param red strength - valid range is 0-255
     * @param green strength - valid range is 0-255
     * @param blue strength - valid range is 0-255
     * @throws java.lang.Exception Exception if the Red, Green or Blue variables are out of range.
     */
    public void setRGB(int red, int green, int blue) throws Exception
    {
        ColorPickerColor colorPickerColor = new ColorPickerColor();
        colorPickerColor.setRGB(red, green, blue);

        this.red = red;
        this.green = green;
        this.blue = blue;
        this.hue = colorPickerColor.getHue();
        this.saturation = colorPickerColor.getSaturation();
        this.brightness = colorPickerColor.getValue();

        tbRed.setText(Integer.toString(this.red));
        tbGreen.setText(Integer.toString(this.green));
        tbBlue.setText(Integer.toString(this.blue));
        tbHue.setText(Integer.toString(this.hue));
        tbSaturation.setText(Integer.toString(this.saturation));
        tbBrightness.setText(Integer.toString(this.brightness));
        tbHexColor.setText(colorPickerColor.getHex());
        setPreview(colorPickerColor.getHex());

        updateSliders();
    }

    /**
     * Called whenever the internal state has been changed and needs to synchronize the other components.
     */
    private void updateSliders()
    {
        // Let the sliders know something's changed
        if (rbHue.getValue()) onClick(rbHue);
        if (rbSaturation.getValue()) onClick(rbSaturation);
        if (rbBrightness.getValue()) onClick(rbBrightness);
        if (rbRed.getValue()) onClick(rbRed);
        if (rbGreen.getValue()) onClick(rbGreen);
        if (rbBlue.getValue()) onClick(rbBlue);
    }

	@Override
	public HandlerRegistration addValueChangeHandler(ValueChangeHandler<String> handler) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public String getValue() {
		return getHexColor();
	}

	@Override
	public void setValue(String value) {
		try {
			setHex(value);
		} catch (Exception e) {
			GWT.log("Bad Hex color code:"+value, e);
		}
	}

	@Override
	public void setValue(String value, boolean fireEvents) {
		setValue(value);
		if(fireEvents){
			ValueChangeEvent.fire(this, value);
		}
	}
}